
#[macro_use]
extern crate actix_web;

use actix_web::dev::{ServiceFactory, ServiceRequest};
use chimes_auth::ChimesAuthorization;
// #[macro_use]
// extern crate wechat;
#[macro_use]
use rbatis::Value;
use rbatis::rbatis::Rbatis;

#[macro_use]
extern crate lazy_static;

// use awc::Client;

use actix_web::http::{StatusCode, header};
use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer, Result, error::{ Error }};
use actix_cors::Cors;


mod handler;
mod entity;
mod query;
mod utils;
use tokio::time;

use crate::utils::{AppConfig, WebServerConfig, ChimesUserAuthService, AppEntryCollect};

use ursa::cl::{ *,issuer::Issuer,prover::Prover,verifier::Verifier};
use ursa::bn::BigNumber;
use ursa::signatures::{SignatureScheme,ed25519::Ed25519Sha512,secp256k1::EcdsaSecp256k1Sha256,bls::normal};
use ursa::bls::*;
use std::collections::HashMap;
#[get("/")]
async fn index_handler(_req: HttpRequest) -> Result<HttpResponse> {
    // response
    Ok(HttpResponse::build(StatusCode::OK)
        .content_type("text/html; charset=utf-8")
        .body("App is running."))
}

use std::io;
use regex::Regex;
use amcl_wrapper::group_elem::GroupElement;
use sha2::Digest;
use chrono::{Datelike, Timelike, Utc};
/// 应用启动入口
//#[actix_web::main]
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() -> std::io::Result<()> {
    // 加载配置文件
    let conf_path = std::env::current_dir().unwrap().as_os_str().to_str().unwrap().to_owned() + "/conf/app.yml";
    log::info!("Current Path: {}", conf_path);
    std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
    // env_logger::init();

    let mut id = String::new();
    println!("Please Input Your identify message:");
    io::stdin().read_line(&mut id)   // 以字符串形式输入一行身份证号码
        .expect("failed to read line.");
    
    //进行身份验证 认证成功返回出生日期
   let birthdate = get_birthate(id.trim());//trim是取出id字符串信息
   let birth = birthdate.unwrap_or(0.to_string());//将取出的出生日期转换成字符串形式
   //println!("this is birth:{}",birth);
    //进入零知识证明算法
    zero_knowledge_proof(&birth);

    match fast_log::init(fast_log::config::Config::new().console()) {
        Ok (_) => {}
        Err(err) => {
            log::info!("An error occurred on the Logger initializing. {}", err);
        }
    };

    // // 加载配置信息
    let mut appconf = AppConfig::get().lock().unwrap();
    appconf.load_yaml(&conf_path.clone()); 
    let conf = appconf.clone();
    drop(appconf);

    let rb = utils::get_rbatis();

    // 启动web服务
    start_web_server(&conf.webserver_conf).await
}

/// web服务启动
async fn start_web_server(webconf: &WebServerConfig) -> std::io::Result<()> {
    // 设置服务器运行ip和端口信息
    let temp_path = webconf.upload_temp_path.clone();
    let ip = format!("{}:{}", "0.0.0.0", webconf.port.clone());
    log::info!("App is listening on {}.", ip.clone());
    // 启动一个web服务
    let cuas = ChimesUserAuthService { system_user: None };
    HttpServer::new(move || {
        App::new()
            .wrap(middleware::Logger::default())
            .wrap(ChimesAuthorization::new(cuas.clone())
                        .header_key(&"Authorization".to_string())
                        .allow(&"/api/v1/auth/login".to_string())
                        .allow(&"/api/v1/auth/code".to_string())
                        .allow(&"/api/v1/auth/logout".to_string())
            )
            .wrap(
                 // 设置允许跨域请求
                Cors::default()
                        .allowed_origin("http://localhost:8080")
                        .allowed_methods(vec!["GET", "POST", "PUT", "DELETE"])
                        .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
                        .allowed_header(header::CONTENT_TYPE)
                        .supports_credentials()
                        .max_age(3600),
            )
            .app_data(awmp::PartsConfig::default().with_file_limit(1000000000).with_temp_dir(temp_path.as_str()))
            .service(index_handler)
            .register_handlers()
    })
    .bind(ip)?
    .run()
    .await
}

///获取身份证出生日期函数
fn get_birthate(id_card:&str) ->Option<String> {
    //定义正则表达式匹配身份证号码
    let re = Regex::new(r"^\d{6}(\d{4})(\d{2})(\d{2})\d{3}[0-9Xx]$").unwrap();
    if let Some(caps) = re.captures(id_card) {
        //如果匹配成功，从捕获组中提取出生日期
        let year = caps.get(1).unwrap().as_str();//转换成&str类型
        let month = caps.get(2).unwrap().as_str();
        let day = caps.get(3).unwrap().as_str();
        //做一步规范日期判断
        if month >"12" || day > "31" {//月数是否符合规范
          return Some("is not legal day".to_string())
        }
        else if month == "02" && day > "29" {//2月天数是否符合规范
          return Some("is not legal day in month".to_string())
        }
        else if year == "0000" {
            return Some("is not legal input".to_string())
        }
        else{
          let birthdate = format!("{}",year);
          return Some(birthdate)
        }
    }//判断身份证长度是否符合规范
    else if id_card.len() < 18 {
      return Some("is not legal input".to_string())
    }
    else {
       None
    }
}

/// 进入零知识证明算法
fn zero_knowledge_proof(prov:&str) {
   //Example of using the Camenisch-Lysyanskaya signature and ZKPs
   let now = Utc::now();
   let current_date = now.num_days_from_ce() / 365;//当前系统天数 /365即为当前年份 :type is i32 
   let age = current_date - prov.parse::<i32>().unwrap();// &str changed i32
   //println!("this is age:{}",age);
   if age >= 18{
       println!("Your age have full 18!!!");
   }else{
       println!("Your age is < 18!!!");
   }
   let mut credential_schema_builder = Issuer::new_credential_schema_builder().unwrap();
   credential_schema_builder.add_attr("age").unwrap();
   let credential_schema = credential_schema_builder.finalize().unwrap();

   let mut non_credential_schema_builder = NonCredentialSchemaBuilder::new().unwrap();
   let non_credential_schema = non_credential_schema_builder.finalize().unwrap();

   //Creating Issuer keys
   let (cred_pub_key, cred_priv_key, cred_key_correctness_proof) =
           Issuer::new_credential_def(&credential_schema, &non_credential_schema, true).unwrap();

   let master_secret = Prover::new_master_secret().unwrap();
   let credential_nonce = new_nonce().unwrap();

   let mut credential_values_builder = Issuer::new_credential_values_builder().unwrap(); 
   credential_values_builder.add_dec_known("age", &age.to_string()).unwrap();
   let cred_values = credential_values_builder.finalize().unwrap();

   //Blinding link secret
   let (blinded_credential_secrets,
        credential_secrets_blinding_factors,
        blinded_credential_secrets_correctness_proof,
       ) = Prover::blind_credential_secrets(
           &cred_pub_key,
           &cred_key_correctness_proof,
           &cred_values,
           &credential_nonce,
       ).unwrap();

   let cred_issuance_nonce = new_nonce().unwrap();

   //Signing the credential
   let (mut cred_signature, signature_correctness_proof) = Issuer::sign_credential(
       "CnEDk9HrMnmiHXEV1WFgbVCRteYnPqsJwrTdcZaNhFVW",
       &blinded_credential_secrets,
       &blinded_credential_secrets_correctness_proof,
       &credential_nonce,
       &cred_issuance_nonce,
       &cred_values,
       &cred_pub_key,
       &cred_priv_key,
   ).unwrap();

   //Unblinding the signature
   Prover::process_credential_signature(
           &mut cred_signature,
           &cred_values,
           &signature_correctness_proof,
           &credential_secrets_blinding_factors,
           &cred_pub_key,
           &cred_issuance_nonce,
           None,
           None,
           None,
       ).unwrap();

   //Create a proof that example_name is over 18
   let mut sub_proof_request_builder = Verifier::new_sub_proof_request_builder().unwrap();
       sub_proof_request_builder
           .add_predicate("age", "GE", 18)
           .unwrap();
   let sub_proof_request = sub_proof_request_builder.finalize().unwrap();
   let mut proof_builder = Prover::new_proof_builder().unwrap();
   proof_builder.add_common_attribute("master_secret").unwrap();
   proof_builder
       .add_sub_proof_request(
           &sub_proof_request,
           &credential_schema,
           &non_credential_schema,
           &cred_signature,
           &cred_values,
           &cred_pub_key,
           None,
           None,
       ).unwrap();

   let proof_request_nonce = new_nonce().unwrap();
   let proof = proof_builder.finalize(&proof_request_nonce).unwrap();

   let mut proof_verifier = Verifier::new_proof_verifier().unwrap();
   proof_verifier
       .add_sub_proof_request(
           &sub_proof_request,
           &credential_schema,
           &non_credential_schema,
           &cred_pub_key,
           None,
           None,
       ).unwrap();
   let is_valid = proof_verifier.verify(&proof, &proof_request_nonce).unwrap();
   println!("example_name >= 18: {}", is_valid);

   //Example of BLS Signature

   //Demoing BLS signature
   let generator = Generator::new().unwrap();
   let sign_key = SignKey::new(None).unwrap();
   let ver_key  = VerKey::new(&generator, &sign_key).unwrap();

   let message = sha2::Sha256::digest(b"This is a test").to_vec();
   let signature = Bls::sign(message.as_slice(), &sign_key).unwrap();

   println!("valid_sig = {}", Bls::verify(&signature, message.as_slice(), &ver_key, &generator).unwrap());

   //Demoing Ed25519 signature
   let scheme = Ed25519Sha512::new();
   let (public, private) = scheme.keypair(None).unwrap();
   let signature = scheme.sign(message.as_slice(), &private).unwrap();
   let res = scheme.verify(message.as_slice(), signature.as_slice(), &public).unwrap();
   println!("verify = {}", res);

   //Demoing BitCoin Curve signature
   let scheme = EcdsaSecp256k1Sha256::new();
   let (public, private) = scheme.keypair(None).unwrap();
   let signature = scheme.sign(message.as_slice(), &private).unwrap();
   let res = scheme.verify(message.as_slice(), signature.as_slice(), &public).unwrap();
   println!("verify = {}", res);
   println!("this is pub_key: {:?}",cred_pub_key);
   //Demoing Advanced BLS signatures
   let mut pks = Vec::new();
   let mut sigs = Vec::new();
   let generator = normal::Generator::generator();
   let msg = b"Hello World!";
   let ctx = b"";
   for _ in 0..10 {
       let (pk, sk) = normal::generate(&generator);
       let sig = normal::Signature::new(msg, Some(ctx), &sk);
       pks.push(pk);
       sigs.push(sig);
   }
   let mut asig = sigs[0].clone();
   asig.combine(&sigs[1..]);
   let mut apk = pks[0].clone();
   apk.combine(&pks[1..]);
   println!("Verity successful to zero_kownledge_range_proof!");
}
